/* COPYRIGHT_CHUNFENG */
#define _XOPEN_SOURCE
#include <unistd.h>
#include <time.h>
#include "cf_std.h"
#include "cf_common.h"
#include "cf_list_file.h"
#include "cf_string.h"
#include "cf_passwd_file.h"
//#define USE_DEBUG_LOG
//#define USE_ERROR_LOG
#include "lcf_log.h"

static int __passwd_atoi(char* start, char** sep)
{
	if((*sep = strchr(start, ':'))){
		if(*sep == start){
			return -1;
		}else{
			return cf_atoll_n(start, *sep-start);
		}
	}else{
		return -2;
	}
}

CFListHead* parse_passwd_line_new(char* start, char* end)
{
	CFPasswd* passwd = (CFPasswd*)malloc(sizeof(CFPasswd));
	char* sep;
	LCF_DBG("\n");
	if((sep = strchr(start, ':'))){
		passwd->name = cf_string_new_start_end(start, sep-1);
		LCF_DBG("name:%s\n", cf_string_get_str(passwd->name));
	}else{
		goto error_out;
	}
    start = sep+1;
	if((sep = strchr(start, ':'))){
		passwd->password = cf_string_new_start_end(start, sep-1);
	}else{
		goto error_out;
	}

	if((passwd->uid = __passwd_atoi(sep+1, &sep)) == -2)
		goto error_out;
	if((passwd->gid = __passwd_atoi(sep+1, &sep)) == -2)
		goto error_out;
    
    start = sep+1;
	if((sep = strchr(start, ':'))){
		passwd->userInfo = cf_string_new_start_end(start, sep-1);
	}else{
		goto error_out;
	}
    
    start = sep+1;
	if((sep = strchr(start, ':'))){
		passwd->home = cf_string_new_start_end(start, sep-1);
	}else{
		goto error_out;
	}
    start = sep+1;
    if(*end == '\n')
		end--;
    passwd->shell = cf_string_new_start_end(start, end);
    
    cf_list_init(&passwd->list);
	return &passwd->list;

error_out:
	free(passwd);
	return NULL;
}

CFPasswd* cf_passwd_get_next(CFPasswd* node)
{
    return container_of(cf_list_get_next(&node->list), CFPasswd, list);
}

void cf_passwd_free(CFPasswd* passwd)
{
	cf_string_free(passwd->name);
	cf_string_free(passwd->password);
	cf_string_free(passwd->userInfo);
	cf_string_free(passwd->home);
	cf_string_free(passwd->shell);
    
	free(passwd);
}

void cf_passwd_free_by_list(CFListHead* list)
{
    cf_passwd_free(container_of(list, CFPasswd, list));
}

int __passwd_write_string(CFString* str, int fd)
{
    write(fd, cf_string_get_str(str), cf_string_get_len(str));
    write(fd, ":", 1);
    return 0;
}

int __passwd_write_int(int n, int fd)
{
    const char *tmp;
    int res = 0;
    if(n >= 0){
        tmp = cf_lltoa(n);
        write(fd, tmp, strlen(tmp));
    }
    write(fd, ":", 1);
    return res;
}

int cf_passwd_write(CFPasswd* passwd, int fd)
{
	LCF_DBG("\n");
    __passwd_write_string(passwd->name, fd);
	LCF_DBG("\n");    
    __passwd_write_string(passwd->password, fd);
    __passwd_write_int(passwd->uid, fd);
    __passwd_write_int(passwd->gid, fd);
    __passwd_write_string(passwd->userInfo, fd);
    __passwd_write_string(passwd->home, fd);
	LCF_DBG("\n");       
    write(fd, cf_string_get_str(passwd->shell), cf_string_get_len(passwd->shell));
	LCF_DBG("\n");    
    return 0;
}

int cf_passwd_write_by_list(CFListHead* list, int fd)
{
    return cf_passwd_write(container_of(list, CFPasswd, list), fd);
}

CFPasswd* cf_passwd_list_get_by_name(CFPasswd* head, const char* name)
{
	CFPasswd* tmpNode = cf_passwd_get_next(head);
	do{
		if(!strcmp(cf_string_get_str(tmpNode->name), name))
			return tmpNode;
		tmpNode= cf_passwd_get_next(tmpNode);
	}while(tmpNode != head);
    return NULL;
}

CFPasswdFile* cf_passwd_file_new(const char* fileUri)
{
    CFPasswdFile* file;
    CFListHead* head;

    file = (CFPasswdFile*)malloc(sizeof(CFPasswdFile));
    if(!file){
        LCF_ERR("Can't alloc for CFPasswdFile\n");
        return NULL;
    }
    head = cf_list_file_new(fileUri, parse_passwd_line_new);
    if(!head){
        LCF_ERR("Parse passwd file: %s failed\n", fileUri);
        free(file);
        return NULL;
    }
    file->fileUri = cf_string_new(fileUri);
    cf_list_init(&file->head.list);
    cf_list_insert_pre(head, &file->head.list);
    return file;
}

void cf_passwd_file_free(CFPasswdFile* file)
{
    cf_list_file_free(&file->head.list, cf_passwd_free_by_list);
    cf_string_free(file->fileUri);
    free(file);
}

int cf_passwd_file_write(CFPasswdFile* file, int fd)
{
    return cf_list_file_write(&file->head.list, fd, cf_passwd_write_by_list);
}

int cf_passwd_file_print(CFPasswdFile* file)
{
    return cf_passwd_file_write(file, 1);
}

int cf_passwd_file_save(CFPasswdFile* file, const char* fileUri)
{
    if(!fileUri)
        return cf_list_file_save(&file->head.list, cf_string_get_str(file->fileUri), cf_passwd_write_by_list);
    return cf_list_file_save(&file->head.list, fileUri, cf_passwd_write_by_list);
}


